"""
@-*- coding: utf-8 -*-
@ python：python 3.8
@ 创建人员:ylx-lingxiao
@ 创建时间:2024/11/7  22:27
@ File:study8.py
@ Explanation:  mysql学习
"""
"""
1.navicat  破解版安装
2.数据库知识
DB的全称是data  base 
数据库实际上是一个文件的集合
是一个存储数据的仓库
本质上来说就是一个文件系统
按照特定的格式或者要求来把数据存储起来，用户可以对数据进行增删改查

关系型数据库  MySQL Oracle DB2     SQL server    这些就是管理数据的软件 也叫数据存储系统，由这个系统来存储我们的数据
并且我们可以在这个系统进行一些增删改查的操作，关系型数据库支持数据之间产生关联，MySQL可以存储这些数据，并且满足我们对业务中的数据
进行我们的预期查询

非关系型数据库  mongodb redis  非关系型数据库，数据之间无关系的数据库，每条数据都是独立的数据


关系型数据库中的数据，就好比我们做的一个用户购买商品的业务--用户注册-商品的类目-供应商的信息-用户选购-生成订单-库存订单变化，等等，这些业务上的数据
存在一定的联系

这也就是企业目前的成本之一  服务器成本 存储成本

数据库服务器  数据库   表关系

所谓的安装数据库服务器只是在机器上装了一个数据库管理系统 比如 MySQL，用来管理多个数据库
开发人员会针对每个应用来创建一个数据库
为了保存应用中的实体数据，我们又会在库中创建多个表，以此来保存业务中的数据



client   链接   服务器上的MySQL成功   进入后  DB   DB   DB  每个DB 下是不同的数据表


sql命令，是专门为操作数据库而建立的操作命令集，只需要发出做什么的命令即可，怎么做不是使用者考虑的
sql语法不区分大小写，每个sql语句用分号结尾，关键字、字段名、表名需要用空格或者逗号隔开，语句可以写一行也可以分开写多行
一个sql语句有没有写完，我们使用分号判定，出现分号，那我认为你的sql写完了    
里边涉及引号的 单双都可以

链接数据库  
主机地址   host 
端口号，一般是3306   port 
用户名   username
密码 即可   password
一般这些都是运维来完成，你需要访问的权限或者说你需要访问哪台机器的数据库，什么权限，，需要联系运维添加后才可以链接到你这个环境的数据库
去公司别人给你这些，你的第一反应是，我先链接上这些数据库

使用navicat 链接  阿里云数据库 mysql版     输入主机名  端口 账号 密码   链接名可以自己输入这个是给你自己看的，如果你有多个数据库
方便你区分数据库
输入完毕后，先点测试链接   成功后点击确定  配置完成

鼠标左键双击点击，链接到数据库

面试题目：------------------------------------------
面试问你们公司的数据库是哪个版本的，你就可以回答5.7，这个版本比较通用，一般你可以在navicat里看到，就是点击链接这个mysql的名称，就可以看到mysql的信息
数据库5.7以后直接就是8.0版本，无中间的版本
原因是老板把公司卖了






数据库常用的操作命令------------------------------------
创建 查看  删除  使用数据库
创建数据库的命令  create database  数据库名称;   数据库名称必须是英文 数字 下划线 
show databases;  显示某个数据库，有返回结果，也可以模糊查询，如----  how database like '%bcbx%'  模糊匹配  
形如  %bcbx37%m%     bcbx37开头或者中间，中间有m或者结尾是m的


drop database 数据库名称;  删除某个数据库    是一个动作，没有返回结果的
use 数据库名称;    选中某个数据库
show tables 查看当前数据库下，所有的表

在哪里输这些命令  链接后 点击查询，新建查询，输入这些命令并执行 即可
mysql 快捷查询 直接鼠标落的区域在库这个位置，最左侧，然后可以直接输入 搜索即可


运行某个sql就是 选中后 选择点击运行选中的   鼠标连续点3下就可以快速选中当前行

navicai自带的筛选功能，还有你可以看到表结构的备注信息




创建  查看 删除  修改数据表----对表本身

我们建表的行为 实际上是在建立表的结构，比如说名称，值的规定，因为数据是后面才存进来的，它是需要规矩的
建表的时候就在规定有多少列， 每列能存放多少的数据，需要设计表的结构


列名  列的数据类型 



列的数据类型 数值型
TINYINT   小整数值    (-128,127)    (0,255)     1字节   0-255
SMALLINT 大整数值  (-32768,32767)   (0,65536)   2字节   256平方
MEDIUMINT  大整数值   3字节  256三次方
INT 大整数值   4字节
BIGINT 极大整数值   8字节
取值的范围越来越大  



FLOAT 单精度  浮点值   4字节
DOUBLE 双精度 浮点值   8字节
DECIMAL 小数值   比如 decimal(5,2)   一共给5个数字，小数点后确定2位，四舍五入  不算小数点  0.01--999.99



unsigned  就是有符号 和无符号   有符号可以表示负数 0 正数
无符号就是 0或正数


字符型
varchar 变长字符串     0-65535字节   变长，按照你实际输入的长度来存   省空间
char  定长字符串 0-255字节   定长不管你输入多少 都按照你规定的大小来存   不省空间，查找速度快
text  长文本数据  0-65535字节


这里的字节和上面的不一致，这里指代的是你文本的长度
比如varchar(10)  不能超过10长度，小于等于10  字母数字符号 汉字都按照1字符长度来计算



日期类型
datetime  8字节  代表了年月日 时分秒     混合日期时间值
date  日期值
time 时间值  时分秒
year 年份值
timestamp     混合日期和时间值 时间戳      1970开始  2038 结束



timestamp   datetime 
相同点和不同点
相同点-都可以表示 年月日 时分秒这样类型的日期
不同点-2者的存储方式不一样，对于tinestamp把客户端插入的时间从当前时区转化为UTC既世界标准时间进行存储，查询时又将其转化为客户端当前时间进行返回，
对于datetime 不做任何改变，基本我们属于原样的输入和输出

两者能存储的时间范围不一样
datetime  公元1000-1-1   9999-12.31
timestamp 存储的范围从19701-1   2038-1-19



创建表的基础命令
CREATE TABLE 表名
(
    field1 datatype,
    field2 datatype,
    field3 datatype
);
field 列名
datatype 列的指定类型

创建表之前，我们要先使用 use 数据库名称，选中数据库或者切换至某个数据库，因为我们是在库下建立表，这个表，是归这个库管理的
列和列之间用逗号隔开  列内使用空格隔开

创建表时，我们要根据保存的数据类型创建对应的列，根据存储的数据类型，定义相应的列的类型
但是其实一般来说，公司里表都是开发来建立，需求对齐后，开发第一时间就是要设计表结构

建表时的约束条件
UNSIGNED   无符号 值从0开始 无负数   一般我们使用为  INT UNSIGNED
ZEROFILL 0填充  当数据的显示长度不够的时候，可以使用填补0的时候来填充至指定长度，字段会自动添加UNSIGNED
NOT NULL 非空约束，表示该字段的值不能为 空
DEFAULT 表示如果插入数据时，没有给这个字段值，那么就使用默认值    默认值要用引号
PRIMARY KEY 主键约束 表示唯一标识 不能为空 且一个表只能有一个主键   一般我们会给主键 +  AUTO_INCREMENT  自增长只能用于数值列  默认从起始值1开始 每次增长1
UNIQUE KEY 唯一值 表示该字段下的值不能重复，可以为空  可以有多个，也称为复合唯一键

举例命令
CREATE TABLE 表名
(
    field1 datatype UNSIGNED ZEROFILL NOT NULL,                   一列同时UNSIGNED ZEROFILL NOT NULL   就要按照这个顺序，NOT NULL 必须排在最后
    field2 datatype DEFAULT 'ADC',
    field3 datatype NOT NULL,
    PRIMARY KEY(field3,field2)
);

主键可以是1列 可以是多列形成的联合主键
像这些名称 我们都可以使用 单引号 引起来，或者不使用也是可以的


COMMENT  相当于一个注释

这些后面比如说 跟着 
INT(1)
VARCHAR(20)

这种就是限定了数据的长度




use 数据库名称
新建表
create user_info(
    user_id int unsigned zerofill not null auto_increment,         自增是只加不减
    user_name varchar(10),      超出长度后截取掉超出的部分
    passwd varchar(10) default '123456',
    reg_time datetime,                                        这里我们如果人为输入异常的时间 则不会处理为正确的，全部处理为0000-00-00 00：00：00
    salary decimal(7,2)               比如说这里整数位只能输入5位 你输入123456  那么提交后 成为 99999.99 取最大值    再比如 1.2568  会四舍五入处理  1.26
    primary key (user_id) 
);



我们点击我们新建的表，右侧就会看到表的信息，navicat工具可能还会对你的sql做一些优化，但是这就是建表的语句，你可以粘贴复制别人的语句创建一样的表

你在工具中新建表  先点击表 点击新建表 就可以在工具中设计表，还能预览相关的sql  想再加一列 那就点新增字段即可，字段的约束如果有默认值，那么这个默认值无论是在sql工具或者语句中都要加引号

我们对于建表语句，不需要我们设计表结构，我们只要能看懂，会用就可以了





我们新建了一个表 自增了到3 此时复制这张表插入数据 从4开始------ 原因就是你复制了之前自增的表，连自增的值也复制进去了

工具建表时，怎么添加unique key    
这个unique key不在navicat新建表中-字段这里，它是在索引这里的  索引中的索引类型
在这里你可以给你的索引起一个名字，然后取给某个字段加上索引
比如说我们给username加了索引，那么原来username 的约束条件就变为了 可以为null 但是有值的时候不可以重复

什么是索引   索引是数据库中用于提高查询效率的技术，类似于目录，一个索引是存储的表中一个特定列的值数据结构，最常见的是B-tree
索引是在表的列上创建，所以关键点就在于 索引 包含一个表中 列的值，并且我们将这些值存在一个数据结构中

索引分为3类
普通索引  仅仅是加速查询   MySQL中基本索引类型没有任何的限制 允许在定义索引的列中插入重复值和空值 纯粹是为了查询数据更快一点
唯一索引，加速查询  列值唯一   可以允许null的情况
主键索引   加速查询 列值唯一 不可以有null  一个表中仅仅能有一个主键 

索引类型
BTREE   将索引值按照一定的算法存在一个树形的数据结构中，二叉树，每次查询从树的入口 root开始 依次遍历所有的node  获取leaf 这是MySQL常用的索引类型 也是默认的

HASH  一次定位，不需要像树形索引逐层查找，效率高，但是 其只能在in  或者= 条件下高效，对于范围查询或者排序及组合索引的效率不高

面试问--你知道什么是索引吗？  答  知道 索引是数据库用于提高查询效率的一门技术
什么情况下会用到索引   如果你的项目中，某个业务，使用到的某张表的 某一列，在我们项目的前端页面是一个可以被用户用来高频次查询的，其次当你这个项目的数据量非常的大
经过你的性能测试发现，每次如果发现从数据库中查，速度慢，就可以考虑给这个列添加索引，加快查询速度
滥用索引会增加服务器的存储成本，其次你后续新增数据的速度会变慢--需要评估加了后是否用户特别需要，因为加 就会导致存储的成本的上升从而导致费用问题

加索引会提升查询的速度 但是存储的成本会翻倍

索引的理解可以想像成你去找快递 图书馆 找书这种

外键
什么是外键  外键用来建立主表和从表的关联关系，为2个表的数据建立连接 约束2个表中数据的一致性和完整性
 两表之间通过某个字段建立的链接或者关系  就叫外键
 
外键类型   
casecade   在父表上 update 或者delete 记录时 ，同步 update 或者delete 掉子表匹配的记录
set null 在父表上 update 或者delete 记录时 ，将字表上匹配记录的列设为null   注意字典的外键列 不能为 not null
no action   如果子表中有匹配的记录 则不允许对父表对应候选键进行update 或者delete 操作
restrict   同  no  action 


一般你是选择在从表中去链接一张主表，链接完成后，看你的外键类型
用户表主表   订单表 从表 中间通过user_id 外键链接

选择cascade 此时删除主表的user_id  从表中会删除这个ID的匹配记录
set null  你把主表上的user_id删除了，从表上这个user_id 对应的值都会被置为null
no action  父表中若这个用户有订单 你不能删除这个用户  必须等子表中 这个用户没订单 既没有这个user_id 后 才能在主表中删除这个用户
restrict 同上

在navicat中 我们新建表中选择外键  我们可以添加  选择你这个子表的字段  选择被引用父表  父表的字段       删除时    更新时的相关操作







修改表

比如说你创建完后 你有些限制  约束忘了加或者要修改
工具层面，你选中一个表，然后可以点击设计表，进行对应的修改
命令层面
向数据表中添加一列
alter table 表名 add 列名 列的数据格式 约束;
alter table user_info add address varchar(10) not null default '123';
默认自动添加到数据表字段的末尾
如果要加在第一列，那在最后面加个first
如果要加在某列的后面则在最后面加个 after 某一列的列名


删除表中的某一列
alter table 表名 drop 列名;

修改列的类型和名称
alter table 表名 modify 列名 数据格式;
alter table user_info modify varchar(20) not null default '123';
alter table 表名 change 旧列名 新列名 数据格式;
修改的同时可以设置默认值
alter table 表名 modify 列名 数据格式 default 100('abc');

改的时候要把原来,比如说不改的约束带上，这个改是覆盖式的改，先清空所有的约束，再给你增加你输入的约束，也就是你的修改要带你预期的所有的约束


修改的时候 表中无数据 你可以随便改，如果表中有数据，那你就要考虑对已有数据的兼容，如何处理这些异常的数据










查看表
显示当前数据库下所有表的名字   show tables
显示某张表的每一列的属性，比如 列名 数据类型 约束   desc 数据表名称    这个方便我们了解表
数据表删除  drop table 表名  
















对数据表中的数据，进行增删改查---对表中的数据
增加，使用insert 语句向表中插入数据
insert into  表名（字段1，字段2...） values（值1，值2...）
insert into user_info(user_id,user_name,passwd,reg_time_salary) values(1,'liming','123666','2024-11-09 21:46:00'.100000)

如果你所有列都给了值。列名 可以省略不写，既你的值的个数等于总列数时
不给值的列  要把这个列名 和值都删除 才能不匹配，但是还是要看列的约束 是不是必填项
如果主键设置了自增 那么这个列和值也可以不给
有默认值的可以不用给




插入的数据应该与字段要求的数据类型相同
数据的大小应该在列的规定范围内
列名不加单双引号

简单来讲 数字类型的不加引号 但是 日期类型 字符串类型的要加引号

值和列 是一一对应的 按照顺序


批量insert    在values 后面 多个符合的括号就行  可以一次插入多个数据
insert into user_info(user_id,user_name,passwd,reg_time_salary) 
values
(1,'liming','123666','2024-11-09 21:46:00'.100000),
(2,'liming2','123666','2024-11-09 21:46:00'.100000),
(3,'liming3','123666','2024-11-09 21:46:00'.100000);


补充0填充 比如说 你入参时 给的是1  入表后展示 00001  但是实际上你where 字句过滤时  还是可以 =1的




update 语句
update 表名 set 列名 = 新值 where 列名 = 某值;
update user_info set passwd = '666666' where user_name = 'liming';  更新这张表 把密码设置为666  针对user_name是liming的这一行
要改哪一列 然后后面的where 条件句来确定是哪一行的



update 语法可以用新值更新原有表 行中的各列
set 子句指示要修改哪些列 和给予哪些值
where 子句指定你要去更新哪些行 没有where子句的话  更新所有行
后面的where 属于条件语句 可以  =  >  <  >=  <=   in  !=

也可以同时改多列
update user_info set passwd = '666666',salary = 88888 where user_name = 'liming'; 


delete    整行整行删除
delete from 表名 where 条件
如果不使用where 子句 则删除表中所有的数据
delete  不能删除某一列的值 ，做这个操作可以使用update    如果你要让这个值为空 那你就通过更新给它一个空字符串即可
update user_info set passwd = ''where user_name = 'liming';  当然你还要看这列的本身的约束条件是否满足你这个入参的值
如果你要直接给null  那你就直接 = null 即可

使用delete 语句 仅仅删除符合where 条件的 行的  数据  不删除其它行 和表本身


对数据的增删改查  这个在navicat工具中也是可以的 比如说你进入表后下方的相关按钮  +   筛选   改值后 点击对勾   选中数据后点击-





select 语句 是查询语句
select * from 表名   查所有的
select field1,field2 from 表名    查哪几个列的
from后面是表名
 
select中可以使用as 语句  
select field as 别名 from 表名
 
where 子句
>  <  =   <=  >=    <> 不等于
between  and             闭区间
in()   是我这个括号内的值 都能取到
like 'zhang%'   模糊匹配
is null 
and  多个条件同时成立
or 多个条件任一成立一个
not   举例  not like  不匹配      is not  null   不为空



%代表零个或者多个任意字符  _ 代表1个字符

'_a%' 第二个字母必须是a






答疑：
如果你建表添加一个数据时，本身的自增ID输入错误了，此时想恢复为之前的，你可以直接去设计表中的选项来调整自增的开始字段，可以修改自增值
这里的保存 你必须把比它大的数字清楚了，不然 它没办法保存


int的数据类型可以决定你这个值的取值范围   后面的（）可以决定这个值的长度     含有-号

比如说 你新建一个列的 数据  为tinyint(4)  因为 还包含了+  -   三位数，有-号 就是4位长度了，超出范围后就按边界值来取

本身你 int()  建表后数据默认为11位  但是你加了 unsigned  就是 10位了  没有了负号

你这个索引加的到底是单个人慢的时候还是多个人慢的时候----
单个人慢的时候 数据库一定有问题，多个人慢的时候，不确定性因素太多网络，带宽，等等因素，但是单个人慢，多个人肯定慢，底层都是去遍历这张表做查询
所以需要优化数据库，具体还是看你性能测试的结果来反馈的





where 子句
<>  不等于  
between and  在什么什么之间  左右闭区间 都可以取到  between  2  and 4 
user_id >= 2  and  user_id <= 4

in (0,2,3) 在0 2 3 中   等于括号里的任意一个都可以,其实也就类比这个下面的or语句
user_id =0 or user_id = 2or user_id =3   


select * from user_table where user_name like '张%';   张开头的
张开头 u结尾的 '张%u'
第二位是i的 '_i%'
倒数第2个是q '%q_'


not  like   不是

不管你是 like   还是 not like  为null的这些行 不在匹配中   这块是针对非null 值去匹配的

查 null 值的
is  null  是null的
is not null  不是null的

SQL出问题就看你这个报错提示 near 附近的  一般错误都在那里出现


运算优先级   not > and > or     括号内的先运算





数据表的排序  聚合命令 分组

排序子句
使用order by 子句对查询结果进行排序

order by 指定排序的列  ASC 升序 desc降序    默认升序 就是从小到大开始      

order by  一般用于select语句的结尾   你就记着查到了才能  排序或者查完了才能排序

排序你可以指定任意列去排序，不一定非要有where 才可以
你只要查出来了 没有where 你就是查的全部，你也可以排序


去重
distinct 对某一列的数据去重      null值也算一种

select distinct 列名 from 表名    显示此列不重复的数据


count 统计总行数
count(*)    包括所有的列  返回表中的总行数  在统计结果时不会忽略 列值为null的行数

count(1)    包括所有的列  1表示一个固定值  无实际含义 统计结果时 不会忽略列值为 null 的行数    和count(*)区别就是执行的效率不同

count(列名) 只包括列名指定列  返回指定列的行数  统计结果时 不统计 列值为null的，不在统计范围内--返回的是目标列中值不为null的总行数

select count(1) from 表名;
select count(*) from 表名;
select count(user_id) from 表名;



组合用法--count(distinct 列名)---返回指定列不重复的行数，统计结果时，会忽略列值为null的行数，不包括空字符串 和0  既列值为null的行数不统计在内


count(列名） > count(1)  如果列名是主键
反之则使用count(1)
主键时 使用count(列名) 效率更快
如果仅1列值  count(*) 更快
如果多列表且无主键 则 count(1) > count(*)




最大值和最小值
max 
min
avg
sum

select max(列名) from 表名;
select min(列名) from 表名;
select avg(列名) from 表名;
select sum(列名) from 表名;

上述都可以+where子句         前面都可以使用as 别名  比如  select max(price) as rich from 表名 where user_id = 2;

select price,order_id from order_info where user_id =2;  列出user_id 是2的 price order_id列

select max(price),order_id from order_info where user_id = 2; 我们不允许这样写，这是错误的写法
你的本意是想找到 这个最大值单价的 order_id 但是我们实际不能这样写
但是实际上代码来看，他们没有匹配的关系，
第一列要的是最大值的，但是第二列你要的是order_id列，这2个没有任何关系，并不会用前述的条件给你匹配后面的
你的order_id 有多个，那怎么给你取来匹配呢？系统只会随机给你取一个，

所以我们的经验是，你前面上了聚合函数后  那你这个地方就不要再加其它的单个的列名了
select max(price),min(price),avg(price),sun(price) from order_info where user_id = 2;
你可以这样写但是不要加单独的列名称，比如
select max(price),min(price),avg(price),sun(price),order_id from order_info where user_id = 2;




limit
select * from 表名 limit m,n;
其中m指定从哪行开始 m从0取值 0表示第一行
n指从 第m+1开始 取n条

select * from 表名 limit 0,2;  从第一行开始 显示2行的结果


如果你只给定一个参数 它表示返回最大的行数目

select * from user_id limit 5; 查询前5个行




limit n  等价于 limit 0,n

这个比排序还靠后  肯定是排完序后再截取





group by 分组聚合

使用group by 子句对列进行分组，针对分组后的结果 每个组 还可以使用having 过滤
然后还可以使用having 子句过滤  having 通常跟在group by 后 它可以作用于组

select field,聚合函数 from 表名 where 子句 group by field;    select 和 from 之间只能跟你分组的这一列，并对这一列使用聚合函数
在这里如果你加别的列 就没有意义，因为分组时，是按照目标列分组 也就是说这一组的这一列的值都一样 ，你使用聚合函数才有意义


select field,聚合函数 from 表名 where 子句 group by field having 聚合函数 过滤条件;

field是列名
聚合函数 指count  sum
使用group by 后只能展示分组的列名+聚合函数的结果  因为其余列已经基于分组这一列合并了



举例

select price,count(1) from order_info group by price;
通过price 分组 然后显示2列 价格 和这个价格的行数  也就是商品的数量

这里不要加别的列 ，没有意义 比如说你加个 order_id 那这个值也是随机拿出来的




select user_id from order_info group by user_id;  这个语句执行后 也相当于去重了 ，我们sq中另外去重的方式是使用 distinct

select user_id，count(*),sum(price),avg(price),max(price) from order_info group by user_id having sum(price) > 20;
select user_id，count(*),sum(price),avg(price),max(price) from order_info where order_status = 'payed' group by user_id having count(1) > 2;
where 的优先级高，执行完后再分组，再过滤 再计算   再排序 再截取

select user_id，count(*),sum(price),avg(price),max(price) from order_info where order_status = 'payed' group by user_id
having sum(price) > 5 order by count(1) desc limit 1 ;



上述我们都是单表查询，此后我们想多表查询，比如我想查张三 下的订单
张三的信息在用户表  订单表通过user_id来和前面的表建立关系

第一种

select user_id from user_info where username = 'zhangsan';
select count(1) from order_info where user_id = 1;


第二种
select count(1) from order_info where user_id in (select user_id from user_info where username = 'zhangsan');
使用in 可以更灵活  in  里边的值可以匹配多个，适用于 模糊查询 比如
 select count(1) from order_info where user_id in (select user_id from user_info where username = 'zhang%');

= 就是指名道姓的，必须是它 完全匹配



第三种

select * from user_info a inner join order_info b on a.user_id = b.user_id where user_name = 'zhangsan';

select user_name,count(1) from user_info a inner join order_info b on a.user_id = b.user_id where user_name = 'zhangsan'
这个sql我们不能这样写，我们的本意是内链接后，建表，然后查出username是张三的人  同时统计行数，但是我们说了 聚合函数和列名不要放在一起
所以这里前面是名称 后面是聚合函数 本身是没有意义的，但是我们可以分组，按哪个列分组，这样 select from之间就可以使用这个列名 以及相关的聚合函数了，具体如下
这个sql我们最后能出来对应的值 也匹配 但是这样就不对了

select user_name,count(1) from user_info a inner join order_info b on a.user_id = b.user_id where user_name = 'zhang%';
这样的话 user_name 可能会有多个 但是聚合函数这列 的值就没办法表示出来了


相关解法是 分组 

select user_name count(1) from user_info a inner join order_info b on a.user_id = b.user_id where user_name = 'zhangsan' 
group by user_name;


select user_name,count(1) from user_info a inner join order_info b on a.user_id = b.user_id where user_name = 'zhang%' group by user_name;









子查询---嵌套在其它查询中的查询

select field1 from table1 where field2 in (select field2 from table2 where field3 = xx)   这里使用in 通吃里边找到的结果，你是一个也可以，是多个结果也可以
一般在子查询中，程序优先运行嵌套在内层的语句，再运行外层的，所以我们编写子查询时，可以从内像外分析我们的sql



连接查询
inner join  内连接    你有 我也有的   交集
获取2个表中字段匹配关系的行 所有信息
2个公有的



left join   左连接    左表特有的部分，和右表结合后 用null     左边全集     左连接表示左表的都要展示出来，展示出来的值在右表找不到对应数据的列就展示null
获取左表的所有行信息，右表即使没有对应匹配的行信息，右表没有匹配部分用null代替
找左表特有的部分

左边的是主表


right join  右连接     右表特有的部分，和左表结合后 能找到匹配的就用原数据，匹配不到的  用null    右边全集
获取右表的所有行信息，左表即使没有对应匹配的行信息，右表没有匹配部分用null代替
可以找右表特有的
右边的是主表




select * from 表名 a inner join 表名 b on a.field = b.field
select * from 表名 a left join 表名 b on a.field = b.field
select * from 表名 a right join 表名 b on a.field = b.field

上述关联完成后就可以看成1张表，然后就可以按1张表来加相关的条件




*展示所有的列   指定展示某张表的哪个列 必须是表名.列名，尤其是 这个列 在A  B 表都有的时候  一定要指定



group by 可以联合分组    比如 group by  a.user_id,user_name     ID一样 且 用户名一样的被分为一组，然后select
后面可以选择性的展示 user_name





select class,team from user_info group by class,team;


嵌套查询的弊端 只能展示外面这张表的数据，里边嵌套的sql都是为了查询到匹配的条件


你想查 买了农夫山泉 水的是哪些人
可以嵌套查  最后只能查到人   可以连接查 所有的表连接起来组成一个大表 然后过滤


select d.user_name from supplier a inner join commodity b on a.supplier_id = b.supplier_id inner join
orders c on c.product_id = b.product_id inner join user_info d on d.user_id = c.user_id where
a.supplier_id = 'nongfushanquan' and b.product_name = 'water';


连接查询是将2张表连接起来，组成一个宽表，包含2张表的所有列


关联或者多表的查询只能你自己来写

navicat工具中 相关可以使用工具提供的 来排序 筛选

like  包含

not like  不包含

在什么内 用 in  完全匹配
  not  in  不在什么范围内 
  
  between and   2头都能取
  
  
  
  
sql语句中 表名 列名 不用加 引号 工具中加了 是为了避免产生冲突



表还可以 自己和自己做关联  比如说你查上级  上级也是ID   这个ID就是你这张表的 user_id 

select b.real_name,b.user_name,b.sex,b.email,a.name,b.post,c.user_name from 
admin_depart a left join admin_user b on a.dept_id = b.dept_id
inner join
admin_user c on b.parent_id = c.user_id
where a.name = '财务室';




你如果想快速通过sql来插入数据 那你就选中一行数据 右键可以复制sql 然后光改里边的值就可以了
还有就是可以通过Python 写一个sql脚本

批量+用户


def make_data(m):
    with open('make_data.sql','w',encoding = 'utf-8') as md:
    md.write('')
    for n in range(1,m+1):
        sql_insert =f 'insert into table(name,sex,age) values('张三{n}','男','{17+n}')
        with open('make_data.sql','a',encoding = 'utf-8') as md:
            md.write(sql_insert+'\n')
            
            
上面加的优化是 保证每次的数据都是干净的不会重复   每次写之前 先覆盖写一个空字符串进入 把之前的数据清除了 再接着覆盖写

 右键 数据库   点击 运行sql文件  选中你刚才的sql文件  开始执行即可，只选第一个就行 下方2个不需要
 
 
 
 
 
 出去答题。人家表名 列名 怎么写 你就怎么写   表现出严谨
 
 
 
 
 使用Python脚本 可以编写sql 造大量的测试数据
 
 
 探索式测试和项目结合看数据库没有看--悟空项目和医疗项目
"""